//
// CGSPrivate.h
// Header file for undocumented CoreGraphics SPI
//
// Arranged by Nicholas Jitkoff
// Based on CGSPrivate.h by Richard Wareham
//
// Contributors:
// Austin Sarner: Shadows
// Jason Harris: Filters, Shadows, Regions
// Kevin Ballard: Warping
// Steve Voida: Workspace notifications
// Tony Arnold: Workspaces notifications enum filters
// Ben Gertzfield: CGSRemoveConnectionNotifyProc
//
// Changes:
// 2.3 - Added the CGSRemoveConnectionNotifyProc method with the help of Ben Gertzfield
// 2.2 - Moved back to CGSPrivate, added more enums to the CGSConnectionNotifyEvent
// 2.1 - Added spaces notifications
// 2.0 - Original Release

#include <Carbon/Carbon.h>

#define CGSConnectionID CGSConnection
#define CGSWindowID CGSWindow
#define CGSDefaultConnection _CGSDefaultConnection()

#ifdef __cplusplus
extern "C" {
#endif

typedef int CGSConnection;
typedef int CGSWindow;
typedef int CGSWorkspace;
typedef int CGSValue;

#pragma mark Listing Windows
/* Get the default connection for the current process. */
extern CGSConnection _CGSDefaultConnection(void);

// Disable/Enable Screen Updates
extern CGError CGSDisableUpdate(CGSConnection cid);
extern CGError CGSReenableUpdate(CGSConnection cid);

#pragma mark Listing Windows

// Get window counts and lists.
extern CGError CGSGetWindowCount(const CGSConnection cid, CGSConnection targetCID, int* outCount);
extern CGError CGSGetWindowList(const CGSConnection cid, CGSConnection targetCID, int count, int* list, int* outCount);

// Get on-screen window counts and lists.
extern CGError CGSGetOnScreenWindowCount(const CGSConnection cid, CGSConnection targetCID, int* outCount);
extern CGError CGSGetOnScreenWindowList(const CGSConnection cid, CGSConnection targetCID, int count, int* list, int* outCount);

// Per-workspace window counts and lists.
extern CGError CGSGetWorkspaceWindowCount(const CGSConnection cid, CGSWorkspace workspaceNumber, int* outCount);
extern CGError CGSGetWorkspaceWindowList(const CGSConnection cid, CGSWorkspace workspaceNumber, int count, int* list, int* outCount);

#pragma mark Window Manipulation

// Window Level
extern CGError CGSGetWindowLevel(const CGSConnection cid, CGSWindow wid, CGWindowLevel* level);
extern CGError CGSSetWindowLevel(const CGSConnection cid, CGSWindow wid, CGWindowLevel level);

// Window ordering
typedef enum _CGSWindowOrderingMode {
  kCGSOrderAbove = 1,                           // Window is ordered above target.
  kCGSOrderBelow = -1,                          // Window is ordered below target.
  kCGSOrderOut = 0                              // Window is removed from the on-screen window list.
} CGSWindowOrderingMode;

extern CGError CGSOrderWindow(const CGSConnection cid, const CGSWindow wid, CGSWindowOrderingMode place, CGSWindow relativeToWindowID /* can be NULL */);
extern CGError CGSWindowIsOrderedIn(const CGSConnection cid, const CGSWindow wid, Boolean* result);

extern CGError CGSUncoverWindow(const CGSConnection cid, const CGSWindow wid);
extern CGError CGSFlushWindow(const CGSConnection cid, const CGSWindow wid, int unknown /* 0 works */);

// Position
extern CGError CGSGetWindowBounds(CGSConnection cid, CGSWindowID wid, CGRect* outBounds);
extern CGError CGSGetScreenRectForWindow(const CGSConnection cid, CGSWindow wid, CGRect* outRect);
extern CGError CGSMoveWindow(const CGSConnection cid, const CGSWindow wid, CGPoint* point);
extern CGError CGSSetWindowTransform(const CGSConnection cid, const CGSWindow wid, CGAffineTransform transform);
extern CGError CGSGetWindowTransform(const CGSConnection cid, const CGSWindow wid, CGAffineTransform* outTransform);
extern CGError CGSSetWindowTransforms(const CGSConnection cid, CGSWindow* wids, CGAffineTransform* transform, int n);

// Alpha
extern CGError CGSSetWindowAlpha(const CGSConnection cid, const CGSWindow wid, float alpha);
extern CGError CGSSetWindowListAlpha(const CGSConnection cid, CGSWindow* wids, int count, float alpha);
extern CGError CGSGetWindowAlpha(const CGSConnection cid, const CGSWindow wid, float* alpha);

// Brightness
extern CGError CGSSetWindowListBrightness(const CGSConnection cid, CGSWindow* wids, float* brightness, int count);

// Workspace
extern CGError CGSMoveWorkspaceWindows(const CGSConnection connection, CGSWorkspace toWorkspace, CGSWorkspace fromWorkspace);
extern CGError CGSMoveWorkspaceWindowList(const CGSConnection connection, CGSWindow* wids, int count, CGSWorkspace toWorkspace);

// Shadow
extern CGError CGSSetWindowShadowAndRimParameters(const CGSConnection cid, CGSWindow wid, float standardDeviation, float density, int offsetX, int offsetY, unsigned int flags);
extern CGError CGSGetWindowShadowAndRimParameters(const CGSConnection cid, CGSWindow wid, float* standardDeviation, float* density, int* offsetX, int* offsetY, unsigned int* flags);

// Properties
extern CGError CGSGetWindowProperty(const CGSConnection cid, CGSWindow wid, CGSValue key, CGSValue* outValue);
extern CGError CGSSetWindowProperty(const CGSConnection cid, CGSWindow wid, CGSValue key, CGSValue* outValue);

// Owner
extern CGError CGSGetWindowOwner(const CGSConnection cid, const CGSWindow wid, CGSConnection* ownerCid);
extern CGError CGSConnectionGetPID(const CGSConnection cid, pid_t* pid, const CGSConnection ownerCid);

#pragma mark Window Tags

typedef enum {
  CGSTagNone = 0,                           // No tags
  CGSTagExposeFade = 0x0002,                 // Fade out when Expose activates.
  CGSTagNoShadow = 0x0008,                   // No window shadow.
  CGSTagTransparent = 0x0200,               // Transparent to mouse clicks.
  CGSTagSticky = 0x0800,                     // Appears on all workspaces.
} CGSWindowTag;

// thirtyTwo must = 32 for some reason.
// tags is a pointer to an array of ints (size 2?). First entry holds window tags.
extern CGError CGSGetWindowTags(const CGSConnection cid, const CGSWindow wid, CGSWindowTag* tags, int thirtyTwo);
extern CGError CGSSetWindowTags(const CGSConnection cid, const CGSWindow wid, CGSWindowTag* tags, int thirtyTwo);
extern CGError CGSClearWindowTags(const CGSConnection cid, const CGSWindow wid, CGSWindowTag* tags, int thirtyTwo);
extern CGError CGSGetWindowEventMask(const CGSConnection cid, const CGSWindow wid, uint32_t* mask);
extern CGError CGSSetWindowEventMask(const CGSConnection cid, const CGSWindow wid, uint32_t mask);

#pragma mark Window Warping

typedef struct {
  float x;
  float y;
} CGSPoint;

typedef struct {
  CGSPoint local;
  CGSPoint global;
} CGSPointWarp;

extern CGError CGSSetWindowWarp(const CGSConnection cid, const CGSWindow wid, int w, int h, CGSPointWarp* mesh);

#pragma mark Window Core Image Filters

typedef void* CGSWindowFilterRef;
extern CGError CGSNewCIFilterByName(CGSConnection cid, CFStringRef filterName, CGSWindowFilterRef* outFilter);
extern CGError CGSAddWindowFilter(CGSConnection cid, CGSWindowID wid, CGSWindowFilterRef filter, int flags);
extern CGError CGSRemoveWindowFilter(CGSConnection cid, CGSWindowID wid, CGSWindowFilterRef filter);
extern CGError CGSReleaseCIFilter(CGSConnection cid, CGSWindowFilterRef filter);
extern CGError CGSSetCIFilterValuesFromDictionary(CGSConnection cid, CGSWindowFilterRef filter, CFDictionaryRef filterValues);

#pragma mark Transitions

typedef enum {
  CGSNone = 0,                    // No transition effect.
  CGSFade,                        // Cross-fade.
  CGSZoom,                        // Zoom/fade towards us.
  CGSReveal,                      // Reveal new desktop under old.
  CGSSlide,                        // Slide old out and new in.
  CGSWarpFade,                    // Warp old and fade out revealing new.
  CGSSwap,                        // Swap desktops over graphically.
  CGSCube,                        // The well-known cube effect.
  CGSWarpSwitch,                  // Warp old, switch and un-warp.
  CGSFlip,                        // Flip over
  CGSTransparentBackgroundMask = (1 << 7)         // OR this with any other type to get a transparent background
} CGSTransitionType;

typedef enum {
  CGSDown,                        // Old desktop moves down.
  CGSLeft,                        // Old desktop moves left.
  CGSRight,                        // Old desktop moves right.
  CGSInRight,                      // CGSSwap: Old desktop moves into screen, new comes from right.
  CGSBottomLeft = 5,              // CGSSwap: Old desktop moves to bl, new comes from tr.
  CGSBottomRight,                  // CGSSwap: Old desktop to br, New from tl.
  CGSDownTopRight,                // CGSSwap: Old desktop moves down, new from tr.
  CGSUp,                          // Old desktop moves up.
  CGSTopLeft,                      // Old desktop moves tl.
  CGSTopRight,                    // CGSSwap: old to tr. new from bl.
  CGSUpBottomRight,                // CGSSwap: old desktop up, new from br.
  CGSInBottom,                    // CGSSwap: old in, new from bottom.
  CGSLeftBottomRight,              // CGSSwap: old one moves left, new from br.
  CGSRightBottomLeft,              // CGSSwap: old one moves right, new from bl.
  CGSInBottomRight,                // CGSSwap: onl one in, new from br.
  CGSInOut                        // CGSSwap: old in, new out.
} CGSTransitionOption;

typedef struct {
  uint32_t unknown1;
  CGSTransitionType type;
  CGSTransitionOption option;
  CGSWindow wid;                /* Can be 0 for full-screen */
  float* backColour;            /* Null for black otherwise pointer to 3 float array with RGB value */
} CGSTransitionSpec;

extern CGError CGSNewTransition(const CGSConnection cid, const CGSTransitionSpec* spec, int* pTransitionHandle);
extern CGError CGSInvokeTransition(const CGSConnection cid, int transitionHandle, float duration);
extern CGError CGSReleaseTransition(const CGSConnection cid, int transitionHandle);

#pragma mark Workspaces

extern CGError CGSGetWorkspace(const CGSConnection cid, CGSWorkspace* workspace);
extern CGError CGSGetWindowWorkspace(const CGSConnection cid, const CGSWindow wid, CGSWorkspace* workspace);
extern CGError CGSSetWorkspace(const CGSConnection cid, CGSWorkspace workspace);
extern CGError CGSSetWorkspaceWithTransition(const CGSConnection cid, CGSWorkspace workspace, CGSTransitionType transition, CGSTransitionOption subtype, float time);

typedef enum {
  CGSScreenResolutionChangedEvent = 100,
  CGSConnectionNotifyEventUnknown2 = 101,
  CGSConnectionNotifyEventUnknown3 = 102,
  CGSConnectionNotifyEventUnknown4 = 103,
  CGSClientEnterFullscreen = 106,
  CGSClientExitFullscreen = 107,
  CGSConnectionNotifyEventUnknown7 = 750,
  CGSConnectionNotifyEventUnknown8 = 751,
  CGSWorkspaceConfigurationDisabledEvent = 761,           // Seems to occur when objects are removed (rows/columns), or disabled
  CGSWorkspaceConfigurationEnabledEvent = 762,            // Seems to occur when objects are added (rows/columns), or enabled
  CGSConnectionNotifyEventUnknown9 = 763,
  CGSConnectionNotifyEventUnknown10 = 764,
  CGSConnectionNotifyEventUnknown11 = 806,
  CGSConnectionNotifyEventUnknown12 = 807,
  CGSConnectionNotifyEventUnknown13 = 1201,            // Seems to occur when applications are launched/quit. Is this a connection being created/destroyed by the application to the window server?
  CGSWorkspaceChangedEvent = 1401,
  CGSConnectionNotifyEventUnknown14 = 1409,
  CGSConnectionNotifyEventUnknown15 = 1410,
  CGSConnectionNotifyEventUnknown16 = 1411,
  CGSConnectionNotifyEventUnknown17 = 1412,
  CGSConnectionNotifyEventUnknown18 = 1500,
  CGSConnectionNotifyEventUnknown19 = 1501,
  CGSConnectionNotifyEventUnknown20 = 1700
} CGSConnectionNotifyEvent;

/* Prototype for the Spaces change notification callback.
 *
 * data1 -- returns whatever value is passed to data1 parameter in CGSRegisterConnectionNotifyProc
 * data2 -- indeterminate (always a large negative integer; seems to be limited to a small set of values)
 * data3 -- indeterminate (always returns the number '4' for me)
 * userParameter -- returns whatever value is passed to userParameter in CGSRegisterConnectionNotifyProc
 */

typedef void (*CGConnectionNotifyProc)(int data1, int data2, int data3, void* userParameter);

/* Register a callback function to receive notifications about when
   the current Space is changing.
 *
 * cid -- Current connection
 * function -- A pointer to the intended callback function (must be in C; cannot be an Objective-C selector)
 * event -- indeterminate (this is hard-coded to 0x579 in Spaces.menu...perhpas some kind of event filter code?) -- use CGSWorkspaceChangedEvent in this for now
 * userParameter -- pointer to user-defined auxiliary information structure; passed directly to callback proc
 */

// For spaces notifications: CGSRegisterConnectionNotifyProc(_CGSDefaultConnection(), spacesCallback, 1401, (void*)userInfo);

extern CGError CGSRegisterConnectionNotifyProc(const CGSConnection cid, CGConnectionNotifyProc function, CGSConnectionNotifyEvent event, void* userParameter);

extern CGError CGSRemoveConnectionNotifyProc(const CGSConnection cid, CGConnectionNotifyProc function, CGSConnectionNotifyEvent event, void* userParameter);

#pragma mark Miscellaneous

// Regions
typedef void* CGSRegionRef;
extern CGError CGSNewRegionWithRect(CGRect const* inRect, CGSRegionRef* outRegion);
extern CGError CGSNewEmptyRegion(CGSRegionRef* outRegion);
extern CGError CGSReleaseRegion(CGSRegionRef region);

// Creating Windows
extern CGError CGSNewWindowWithOpaqueShape(CGSConnection cid,
    int always2,
    float x,
    float y,
    CGSRegionRef shape,
    CGSRegionRef opaqueShape,
    int unknown1,
    void* unknownPtr,
    int always32,
    CGSWindowID* outWID);
extern CGError CGSReleaseWindow(CGSConnection cid, CGSWindowID wid);
extern CGContextRef CGWindowContextCreate(CGSConnection cid, CGSWindowID wid, void* unknown);

// Values
extern int CGSIntegerValue(CGSValue intVal);
extern void* CGSReleaseGenericObj(void*);

// Deprecated in 10.5
extern CGSValue CGSCreateCStringNoCopy(const char* str);         // Normal CFStrings will work
extern CGSValue CGSCreateCString(const char* str);
extern char* CGSCStringValue(CGSValue string);

#pragma mark Debugging

// These all create files called /tmp/WindowServer + suffix
#define kCGSDumpWindowInfo 0x80000001 // .winfo.out
#define kCGSDumpConnectionInfo 0x80000002 // .cinfo.out
#define kCGSDumpKeyInfo 0x8000000e // .keyinfo.out
#define kCGSDumpSurfaceInfo 0x80000010 // .sinfo.out
#define kCGSDumpGLInfo 0x80000013 // .glinfo.out
#define kCGSDumpShadowInfo 0x80000014 // .shinfo.out
#define kCGSDumpStoragesAndCachesInfo 0x80000015 // .scinfo.out
#define kCGSDumpWindowPlistInfo 0x80000017 // .winfo.plist
// Other flags:
#define kCGSDebugOptionNormal 0 // Reset everything
#define kCGSFlashScreenUpdates 4 // This is probably what the checkbox in Quartz Debug calls internally
typedef unsigned long CGSDebugOptions;

extern void CGSSetDebugOptions(CGSDebugOptions options);

// Missing functions

// CGSIntersectRegionWithRect
// CGSSetWindowTransformsAtPlacement
// CGSSetWindowListGlobalClipShape
// extern CGError CGSWindowAddRectToDirtyShape(const CGSConnection cid, const CGSWindow wid, CGRect *rect);

#ifdef __cplusplus
}
#endif
